/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// @ts-nocheck
import { Configuration } from './config/Configuration'
import { Match } from './config/Match'
import { LoggerContext } from './slf4j/loggercontext'
import { Level } from './Level'
import { Appender } from './Appender'
import { FilterEnum } from './FilterEnum'
import { Filter } from './config/Filter'
import { ILogger } from './slf4j/ILogger'
import { PreferencesUtils } from './util/PreferencesUtils'
import { RollingFileAppender } from './appender/RollingFileAppender'
import { DBAppender } from './appender/DBAppender'
import { SiftingAppender } from './appender/SiftingAppender'
import { SocketAppender } from './appender/SocketAppender'
import { SMTPAppender } from './appender/SMTPAppender'
import { FileIO } from './io/FileIO'
import { HiLog } from './log/HiLog';
import { Encoder } from './encoder/Encoder';

export class Logger implements ILogger {
    private name: string
    private level: Level
    static ROOT_LOGGER_NAME = "ROOT"
    private loggerContext: LoggerContext
    private TAG = 'logback'
    private effectiveLevelInt: number
    private mailCount: number
    private configure: Configuration = globalThis.configure
    private FORMAT = 'yyyy-MM-dd HH:mm:ss'
    private dBAppender: DBAppender
    private socketAppender: SocketAppender
    private SMTPAppender: SMTPAppender
    private count = 0
    private mailMsg = ''

    constructor(name: string, loggerContext: LoggerContext) {
        this.name = name
        this.loggerContext = loggerContext
        if (this.configure != null && this.configure.file != null) {
            FileIO.create_fileIo(this.configure.file)
        }
        if (this.configure != null && this.configure.rollingFile != null) {
            FileIO.create_fileIo(this.configure.rollingFile)
            PreferencesUtils.putData(PreferencesUtils.CURRENT_TIME, PreferencesUtils.CURRENT_TIME, new Date().getTime(), () => {
            })
        }
        if (this.configure != null) {
            this.dBAppender = new DBAppender()
            this.dBAppender.createRdb(this.configure)
            this.socketAppender = new SocketAppender()
            this.socketAppender.bind(this.loggerContext, this.configure)
            this.SMTPAppender = new SMTPAppender()
            this.SMTPAppender.bind(this.loggerContext, this.configure)
        }
    }

    public getName(): string {
        return this.name
    }

    public trace(msg: string) {
        this.filterAndLog(Level.TRACE, msg)
    }

    public debug(msg: string) {
        this.filterAndLog(Level.DEBUG, msg)
    }

    public info(msg: string) {
        this.filterAndLog(Level.INFO, msg)
    }

    public warn(msg: string) {
        this.filterAndLog(Level.WARN, msg)
    }

    public error(msg: string) {
        this.filterAndLog(Level.ERROR, msg)
    }

    public fatal(msg: string) {
        this.filterAndLog(Level.FATAL, msg)
    }

    private filterAndLog(level: Level, msg: string) {
        this.level = level
        if (this.configure == null) {
            if (this.effectiveLevelInt > this.level.getLevelInt()) {
                return
            }
            msg = this.level.getLevelStr() + ' ' + this.loggerContext.getLoggerName() + ' ' + msg
            HiLog.logger(this.level.getLevelStr(), msg)
        } else {
            var pattern = ''
            var className = ''
            var filter: Filter
            if (this.configure.logger == null) { //root
                this.effectiveLevelInt = this.configure.root.level.getLevelInt()
                for (var i = 0; i < this.configure.appender.length; i++) {
                    if (this.configure.root.appenderRef.ref == this.configure.appender[i].name) {
                        pattern = this.configure.appender[i].encoder.pattern.msg
                        className = this.configure.appender[i].className
                    }
                }
            } else { //logger
                for (var i = 0; i < this.configure.logger.length; i++) {
                    if (this.loggerContext.getLoggerName() == this.configure.logger[i].name) {
                        this.effectiveLevelInt = this.configure.logger[i].level.getLevelInt()
                        className = this.configure.appender[i].className
                        if (this.configure.appender[i].encoder != null) {
                            pattern = this.configure.appender[i].encoder.pattern.msg
                        }
                        if (this.configure.appender[i].filter != null) {
                            filter = this.configure.appender[i].filter
                            this.effectiveLevelInt = this.configure.appender[i].filter.level.getLevelInt()
                        }
                        if (this.configure.appender[i].mailCount != null) {
                            this.mailCount = this.configure.appender[i].mailCount
                        }
                    }
                }
            }
            if (this.effectiveLevelInt > this.level.getLevelInt()) {
                return
            }
            switch (className) {
                case Appender.CONSOLE:
                    if (filter != null) {
                        if (filter.className == FilterEnum.LEVEL) {
                            if (filter.onMatch == Match.ACCEPT && filter.onMismatch == Match.DENY) {
                                if (this.level.getLevelStr() == filter.level.getLevelStr()) {
                                    HiLog.logger(filter.level.getLevelStr(), Encoder.encoders(this.loggerContext, pattern, this.level.getLevelStr(), msg))
                                }
                                return
                            }
                        } else if (filter.className == FilterEnum.THRESHOLD) {
                            HiLog.logger(filter.level.getLevelStr(), Encoder.encoders(this.loggerContext, pattern, this.level.getLevelStr(), msg))
                        }
                    } else {
                        HiLog.logger(this.level.getLevelStr(), Encoder.encoders(this.loggerContext, pattern, this.level.getLevelStr(), msg))
                    }
                    break
                case Appender.FILE:
                    if (filter != null) {
                        if (filter.className == FilterEnum.LEVEL) {
                            if (filter.onMatch == Match.ACCEPT && filter.onMismatch == Match.DENY) {
                                if (this.level.getLevelStr() == filter.level.getLevelStr()) {
                                    FileIO.write_fileIo(Encoder.encoders(this.loggerContext, pattern, this.level.getLevelStr(), msg))
                                }
                                return
                            }
                        } else if (filter.className == FilterEnum.THRESHOLD) {
                            FileIO.write_fileIo(Encoder.encoders(this.loggerContext, pattern, this.level.getLevelStr(), msg))
                        }
                    } else {
                        FileIO.write_fileIo(Encoder.encoders(this.loggerContext, pattern, this.level.getLevelStr(), msg))
                    }
                    break
                case Appender.ROLLING_FILE:
                    new RollingFileAppender().start(this.loggerContext, this.configure, this.level, msg)
                    break
                case Appender.DB:
                    this.dBAppender.start(this.loggerContext, this.configure, this.level, msg)
                    break
                case Appender.SIFT:
                    new SiftingAppender().start(this.loggerContext, this.configure, this.level, msg)
                    break
                case Appender.SOCKET:
                    this.socketAppender.start(this.level, msg)
                    break
                case Appender.SMTP:
                    this.count++
                    this.mailMsg += (level.getLevelStr() + ' ' + msg + '\n')
                    if ((this.count % this.mailCount) == 0) {
                        this.SMTPAppender.start(this.level, this.mailMsg)
                    }
                    break
            }
        }
    }

    public setLevel(level: Level) {
        this.level = level
        this.effectiveLevelInt = level.getLevelInt();
    }
}